package com.gzhryc.common.event;

import com.gzhryc.common.logging.Logger;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 延迟处理服务
 * 
 * @author 张浩
 * @version 2017-1-11
 */
public class DelayHandleService {

	static Logger log = Logger.getLogger(DelayHandleService.class);

	static DelayHandleService self;

	public static DelayHandleService get() {
		if (self == null) {
			self = new DelayHandleService();
		}
		return self;
	}

	BlockingQueue<IDelayEvent> Queue = new LinkedBlockingQueue<IDelayEvent>();
	AtomicBoolean isRun = new AtomicBoolean(false);
	ConcurrentHashMap<Integer, Task> Tasks = new ConcurrentHashMap<Integer, Task>();
	AbsDelayHandler<?> Handler = new DefaultDelayHandler();

	public DelayHandleService() {
		this.Queue = new LinkedBlockingQueue<IDelayEvent>();
		this.Tasks = new ConcurrentHashMap<Integer, Task>();
		this.Handler = new DefaultDelayHandler();
		this.isRun = new AtomicBoolean(false);
	}

	/**
	 * 添加延迟处理程序
	 * 
	 * @param handler
	 */
	public <T extends AbsDelayHandler<?>> void addHandler(T handler) {
		Handler.setNextHandler(handler);
	}

	/**
	 * 添加延迟事件
	 * 
	 * @param event
	 * @return
	 */
	public <T extends IDelayEvent> boolean addEvent(T event) {
		try {
			if (isRun.get()) {
				Queue.put(event);
				return true;
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * 启动服务
	 * 
	 * @param threadNum 线程数
	 */
	public void run(int threadNum) {
		if (isRun.compareAndSet(false, true)) {
			for (int i = 0; i < threadNum; i++) {
				Task task = new Task(i);
				Tasks.put(task.getIndex(), task);
				task.start();
			}
			log.info("启动延迟执行服务，线程数：" + threadNum);
		}
	}

	public void run() {
		int poolSize = Runtime.getRuntime().availableProcessors();
		run(poolSize * 2);
	}

	/**
	 * 关闭服务
	 */
	public void close() {
		if (isRun.compareAndSet(true, false)) {
			int total = Tasks.size();
			for (int i = 0; i < total; i++) {
				Queue.add(new EmptyDelayEvent());
			}
		}
	}

	public boolean isRun() {
		return this.isRun.get();
	}

	public boolean contains(Class<?> clazz) {
		return contains(Handler, clazz);
	}

	private boolean contains(AbsDelayHandler<?> handler, Class<?> clazz) {
		if (handler.getClass().equals(clazz)) {
			return true;
		} else if (handler.getNextHandler() != null) {
			return contains(handler.getNextHandler(), clazz);
		}
		return false;
	}

	private class Task extends Thread {

		final Integer index;

		public Task(Integer index) {
			this.index = index;
		}

		public void run() {
			while (isRun.get()) {
				try {
					IDelayEvent event = Queue.take();
					Handler.intercept(event);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			// 移除自己
			Tasks.remove(index);
		}

		public Integer getIndex() {
			return this.index;
		}
	}

	public class EmptyDelayEvent implements IDelayEvent {

		private static final long serialVersionUID = 1L;
	}

	public class DefaultDelayHandler extends AbsDelayHandler<IDelayEvent> {
		@Override
		public boolean execute(IDelayEvent event) {
			return true;
		}
	}
}
